/**
 * 1. Promise 就是一个类，在执行这个类的时候需要传递一个执行器进去，执行器会立即执行
 * 2. Promise 中有三种状态，分别为：成功（fulfilled），失败（rejected），等待（pending）
 *    pending -> fulfilled
 *    pending -> rejected
 *    状态一旦确定就不可更改
 * 3. resolve和reject函数是用来更改状态的
 *    resolve：fulfilled
 *    reject：rejected 
 * 4. then 方法判断状态，如果状态成功 => 调用成功的回调函数，如果状态失败 => 调用失败回调函数，并且then方法是被定义在原型对象中
 * 5. then 成功回调有一个参数， 表示成功之后的值，失败回调有一个参数， 表示失败之后的原因
 * 6. 同一个promise的then可以被多次调用，分为异步和同步
 * 7. then 可以被链式调调用， 后面的then方法回调函数拿到的值是上一个then方法的回调函数返回值
 * 8. try catch 捕获错误
 * 9. 状态传递
 * 10. all 方法的实现
 * 11. resolve 方法实现
 * 12. finally 方法实现
 * 13. catch 方法实现
 */
interface Status{
    PENDING: 'pending',      // 等待
    FULFILLED: 'fulfilled',  // 成功
    REJECTED: 'rejected'     // 失败
}
const statusObj: Status = {
    PENDING: 'pending',
    FULFILLED: 'fulfilled',
    REJECTED: 'rejected'
};
export class MyPromise {
    // Promise 状态存储
    status: string = statusObj.PENDING;
    // 成功之后的值
    value! : any;
    // 失败之后的值
    reason!: any;
    // 成功回调
    successCallback: Array<any> = [];
    // 失败回调
    failCallback: Array<any> = [];
    constructor(executor: Function) {
        try {
            executor(this.resolve, this.reject);
        } catch (e){
            this.reject(e);
        }
    }

    resolve = (value: any): void => {
        // 如果状态不是等待 阻止程序向下执行
        if(this.status !== statusObj.PENDING) {
            return;
        }
        // 将状态更改为成功
        this.status = statusObj.FULFILLED;
        // 保存成功之后的值
        this.value = value;
        // 判断成功回调是否存在， 如果存在，执行
        // this.successCallback && this.successCallback(this.value);
        while(this.successCallback.length) {
            this.successCallback.shift()!();
        }
    }

    reject = (reason: any): void => {
        // 如果状态不是等待 阻止程序向下执行
        if(this.status !== statusObj.PENDING) {
            return;
        }
        // 将状态更改为失败
        this.status = statusObj.REJECTED;
        // 保存失败后的原因
        this.reason = reason;
        // this.failCallback && this.failCallback(this.reason);
        while(this.failCallback.length) {
            this.failCallback.shift()!();
        }
    }
    
    then = (successCallback: Function, failCallback: Function): MyPromise => {
        successCallback = successCallback ? successCallback : (value: any) => value;
        failCallback = failCallback ? failCallback : (reason: any) => { throw reason };
        const substitute =  new MyPromise((resolve: Function, reject: Function) => {
            const exception = (flag: boolean) => {
                setTimeout(()=> {
                    try {
                        let result = flag? successCallback(this.value): failCallback(this.reason);
                        // 判断 x 的值是普通值还是promise对象
                        // 如果是普通值 直接用resolve
                        // 如果是promise对象 查看promise对象返回的结果
                        // 再根据promise对象返回的结果 决定调用resolve 还是调用 reject
                        this.resolvePromise(substitute, result, resolve, reject);
                    } catch (error) {
                        reject(error);
                    }
                    
                },0);
            }
            // 判断状态
            if (this.status === statusObj.FULFILLED) {
                exception(true);
            } else if(this.status === statusObj.REJECTED) {
                exception(false);
            } else {
                // 等待处理
                // 存储成功回调和失败回调函数
                this.successCallback.push(() => {
                    exception(true);
                });
                this.failCallback.push(() => {
                    exception(false);
                });
            }
        })

        return substitute;
    }
    
    resolvePromise = (substitute: MyPromise, result: MyPromise | Function, resolve: Function, reject: Function): void => {
        if (substitute === result) {
            return reject (new TypeError('Chaining cycle detected for promise #<Promse>'))
        }
        if (result instanceof MyPromise) {
            // promise 对象
            result.then(resolve, reject);
        } else {
            // 普通值
            resolve(result);
        }
    }

    finally (callback: Function): MyPromise{
        return this.then((value: any) => {
            return MyPromise.resolve(callback()).then(() => value);
        }, (reason: any) => {
            return MyPromise.resolve(callback()).then(() => { throw reason });
        })
    }

    catch (callback: Function): MyPromise {
        return this.then(() => {}, callback);
    }

    static all = (array: Array<MyPromise>): MyPromise => {
        let result: Array<any> = [];
        let count = 0;
        return new MyPromise((resolve: Function, reject: Function) => {
            const addData = (key: number, value: MyPromise | Function) => {
                result[key] = value;
                count ++;
                if(count === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise 对象
                    current.then((value: Function | MyPromise) => addData(i, value), (reason: any) => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }

    /**
     * resolve 实现
     * @param value 
     */
    static resolve = (value: MyPromise | any) : MyPromise | any => {
        if(value instanceof MyPromise) return value;
        return new MyPromise((resolve: Function) => resolve(value));
    }
}
